package com.yy.QSManage.tool;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.KeyUtil;
import cn.hutool.crypto.asymmetric.AsymmetricAlgorithm;
import cn.hutool.json.JSONObject;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import cn.hutool.jwt.signers.JWTSigner;
import cn.hutool.jwt.signers.JWTSignerUtil;
import com.yy.QSManage.exception.ServiceException;

import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class JwtTool {

    /**
     * token有效时间 3 小时
     */
    private static final int EFFECTION_TIME = 4;
    public static final String TOKEN = "token";
    public static final String PUBLIC_KEY = "publicKey";

    /**
     * 生成token
     * @param map 携带参数
     * @return token和公钥
     */
    public static Map<String, String> createToken(Map<String, Object> map){
        Map<String, String> resultMap = new HashMap<>();
        KeyPair keyPair = KeyUtil.generateKeyPair(AsymmetricAlgorithm.RSA.getValue());
        PrivateKey privateKey = keyPair.getPrivate();
//        String privateKeyStr = JwtTool.bytesToBase64(privateKey.getEncoded());
        PublicKey publicKey = keyPair.getPublic();
        String publicKeyStr = JwtTool.bytesToBase64(publicKey.getEncoded());
        // 私钥加密
        JWTSigner jwtSigner = JWTSignerUtil.rs256(privateKey);
        String token = JWT
                .create()
                .addPayloads(map)
                .setSigner(jwtSigner)
                .setExpiresAt(DateUtil.offsetHour(new Date(), EFFECTION_TIME))
                .sign();
        resultMap.put(TOKEN, token);
        resultMap.put(PUBLIC_KEY, publicKeyStr);
        return resultMap;
    }

    /**
     * token验证
     * @param token
     * @param publicKey
     */
    public static void verifyToken(String token, String publicKey){
        if(StrUtil.isEmpty(token) || StrUtil.isEmpty(publicKey)){
            throw new ServiceException("token验证失败,参数异常");
        }
        byte[] publicKeyByte = JwtTool.base64ToBytes(publicKey);
        PublicKey publicKey1 = KeyUtil.generateRSAPublicKey(publicKeyByte);
        JWTSigner signer = JWTSignerUtil.rs256(publicKey1);
        boolean verify = JWTUtil.verify(token, signer);
        if(!verify){
            throw new ServiceException("token验证失败");
        }
    }

    /**
     * 获取token携带某个参数
     * @param token
     * @param publicKey
     * @param parseKey
     * @return
     */
    public static Object getPayload(String token, String publicKey,String parseKey){
        verifyToken(token, publicKey);
        JWT jwt = JWTUtil.parseToken(token);
        return jwt.getPayload(parseKey);
    }

    /**
     * 获取token携带的所有参数
     * @param token
     * @param publicKey
     * @return
     */
    public static JSONObject getPayloads(String token, String publicKey){
        verifyToken(token, publicKey);
        JWT jwt = JWTUtil.parseToken(token);
        return jwt.getPayloads();
    }

    /**
     * 字节数组转Base64编码
     *
     * @param bytes 字节数组
     * @return Base64编码
     */
    private static String bytesToBase64(byte[] bytes) {
        byte[] encodedBytes = Base64.getEncoder().encode(bytes);
        return new String(encodedBytes, StandardCharsets.UTF_8);
    }

    /**
     * Base64编码转字节数组
     *
     * @param base64Str Base64编码
     * @return 字节数组
     */
    private static byte[] base64ToBytes(String base64Str) {
        byte[] bytes = base64Str.getBytes(StandardCharsets.UTF_8);
        return Base64.getDecoder().decode(bytes);
    }
}
